feat(W-23159744): per-user persistent feature flags (Android)#2937
Open
wmathurin wants to merge 9 commits into
Open
feat(W-23159744): per-user persistent feature flags (Android)#2937wmathurin wants to merge 9 commits into
wmathurin wants to merge 9 commits into
Conversation
Implements per-user feature flag storage and hydration so each user account's active features are accurately reflected in the User-Agent string across app restarts. - UserAccount: featureFlags field (Set<String>), serialized to JSON, persisted via AccountManager (KEY_FEATURE_FLAGS, encrypted comma-separated) - SalesforceSDKManager: perUserFeatures map (ConcurrentHashMap<String,ConcurrentSkipListSet>), getUserAgent(qualifier, user) unions global + per-user flags, registerUsedAppFeature/unregisterUsedAppFeature per-user overloads, hydratePerUserFeatures() called from init block, isGlobalFeatureRegistered() helper - LoginActivity: completedViaBrowserTab flag captures Custom Tab completion (covers both regular and Login for Admin); onAuthFlowSuccess promotes BW/WD/QR transient global flags to per-user - AuthenticationUtilities: BA/SL flags registered per-user - SmartStoreSDKManager: SU flag registered per-user - SyncManager/LayoutSyncManager/MetadataSyncManager: MS/Layout/Metadata flags per-user - SalesforceHybridSDKManager: getUserAgent(qualifier, user) override - UserAccountTest, SalesforceSDKManagerTests: new unit tests
Generated by 🚫 Danger |
FEATURE_BROWSER_LOGIN must appear in the UA for requests made during the login session. Register it globally in loadLoginPageInCustomTab() (alongside completedViaBrowserTab = true), then clear global and promote to per-user at onAuthFlowSuccess — matching the WD/QR pattern.
hydratePerUserFeatures() is called from the init block, before the userAccountManager lazy delegate is set up. Call UserAccountManager.getInstance() directly instead of going through the lazy property.
…tion to UI tests - Add USER_AGENT_CONTENT_DESC constant to AuthFlowTesterActivity - Add getUserAgentString() helper and User Agent InfoRowView to UserCredentialsView - Include User Agent in JSON export of credentials card - Add contentDescription param to InfoRowView (defaults to label) to allow distinct semantic IDs - Add validateUserAgent() to AuthFlowTesterPageObject: asserts SalesforceMobileSDK/ prefix, ftr_ segment, and BW/WD/MU flag presence/absence based on login config - Thread isMultiUser param through loginAndValidate() and call validateUserAgent() after login - Update RefreshTokenMigrationTests override to include new isMultiUser param - Add loginOtherUserAndValidate/switchToUserAndValidate UA validation in MultiUserLoginTests - Add testAdvancedAuthUser_HasBWFlag_RegularAuthUser_DoesNot test Note: pre-existing WebView 5s timeout failures in BootConfigLoginTests, NegativeLoginTests, RefreshTokenMigrationTests are infrastructure flakiness unrelated to these changes.
brandonpage
approved these changes
Jun 25, 2026
…Agent into public/private overloads validateUserAgent() fetches the UA once and delegates to a private overload taking ua: String. validateUser() calls the private overload using credentials already loaded, eliminating a second UI traversal.
…gisterUsedAppFeature handleScreenLockPolicy and handleBiometricAuthPolicy now call registerUsedAppFeature(feature, account) / unregisterUsedAppFeature(feature, account). Update the 6 mock verifications accordingly.
Contributor
Author
|
Retriggering CI — MobileSync and SalesforceHybrid failures are org rate-limit / connectivity flakes (SyncManagerTest.java:95 'Creates failed', 60s timeouts in MobileSyncJSTest), unrelated to this PR's changes. SalesforceSDK, SmartStore, and UI tests all pass. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
featureFlagsfield toUserAccount(Set), serialized to JSON and persisted via AccountManager as an encrypted comma-separated string underKEY_FEATURE_FLAGSSalesforceSDKManagergains per-user overloads forregisterUsedAppFeature/unregisterUsedAppFeature,getUserAgent(qualifier, user)(returns global ∪ per-user union),isGlobalFeatureRegistered(), andhydratePerUserFeatures()called frominitLoginActivity:completedViaBrowserTabflag captures Custom Tab completion for both regular browser login and Login for Admin;onAuthFlowSuccesspromotes BW/WD/QR flags to per-userAuthenticationUtilitiesregistered per-user; SU inSmartStoreSDKManager; MS/Layout/Metadata in their respective sync managersSalesforceHybridSDKManageraddsgetUserAgent(qualifier, user)overrideUserAccountTestandSalesforceSDKManagerTestsGUS Stories
Test plan
./gradlew :libs:SalesforceSDK:assembleAndroidTest— BUILD SUCCESSFUL./gradlew :libs:SalesforceSDK:testDebugUnitTest— BUILD SUCCESSFUL./gradlew :libs:SalesforceSDK:lint— BUILD SUCCESSFUL (no new warnings)connectedAndroidTest) — require connected device/emulator, run in CI